package cn.com.bsoft.mobile.service


import cn.com.bsoft.mobile.dao.*
import cn.com.bsoft.mobile.entity.*
import cn.com.bsoft.mobile.model.AppMessageRsp
import cn.com.bsoft.mobile.model.CreateAppMessageReq
import cn.com.bsoft.mobile.model.QueryAppMessageReq
import cn.net.xyan.blossom.kotlin.AllOpen
import cn.net.xyan.blossom.kotlin.StatusAndMessageError

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.domain.Specifications
import org.springframework.http.MediaType
import org.springframework.transaction.annotation.Transactional
import java.util.*
import javax.persistence.criteria.Join

interface AppMessageService {
    fun createSimpleMessage(content: String, suite: MobileAppSuite?, users: List<MobileUser>?): List<AppMessage>

    fun createMessage(req:CreateAppMessageReq):List<AppMessage>

    fun queryMessage(req: QueryAppMessageReq, pageable: Pageable?): List<AppMessage>
    fun readMessage(messageID: String): AppMessage

    fun createSendMessageJob(msg: AppMessage): List<AppMessageJob>

    fun convertMessage(msg: AppMessage): AppMessageRsp
}

@AllOpen
class DefaultAppMessageService : AppMessageService {


    @Autowired
    lateinit var appDao: MobileAppDao

    @Autowired
    lateinit var appMessageDao: AppMessageDao

    @Autowired
    lateinit var mobileUserDao: MobileUserDao

    @Autowired
    lateinit var jobDao: AppMessageJobDao

    @Autowired
    lateinit var suiteDao: MobileAppSuiteDao

    @Autowired
    lateinit var deviceService: MobileDeviceService

    override fun convertMessage(msg: AppMessage): AppMessageRsp {
        val rsp = AppMessageRsp()
        rsp.messageID = msg.messageID
        rsp.contentType = msg.contentType
        rsp.createDate = msg.createDate
        rsp.messageBody = msg.messageBody
        rsp.readStatus = msg.readStatus
        rsp.title = msg.msgTitle
        rsp.extra = msg.extra

        return rsp
    }

    override fun createMessage(req: CreateAppMessageReq): List<AppMessage> {

        val result = LinkedList<AppMessage>()

        var users = LinkedList<MobileUser>()

        req.user?.forEach {
            if (it != null){
                val u = mobileUserDao.findOne(it)

                if (u!= null){
                    users.add(u)
                }
            }
        }

        val suite = suiteDao.findOne(req.suite)

        var appMessage = AppMessage(users, suite)

        appMessage.msgTitle = req.title
        appMessage.messageBody = req.body?:""
        appMessage.contentType = req.contentType?:MediaType.TEXT_PLAIN_VALUE
        appMessage.extra = req.extra
        appMessage.action = req.action

        appMessage = appMessageDao.saveAndFlush(appMessage)

        createSendMessageJob(appMessage)

        result.add(appMessage)
        //  }

        return result
    }

    override fun createSimpleMessage(content: String, suite: MobileAppSuite?, users: List<MobileUser>?): List<AppMessage> {
        val msgUser = users ?: mobileUserDao.findAll()
        val mobileAppSuite = suite ?: suiteDao.findAll().first()

        val result = LinkedList<AppMessage>()

        // mobileAppSuite.apps?.forEach {
        var appMessage = AppMessage(msgUser, mobileAppSuite)

        appMessage.messageBody = content
        appMessage.contentType = MediaType.TEXT_PLAIN_VALUE
        appMessage.msgTitle = "SimpleTitle"

        appMessage = appMessageDao.saveAndFlush(appMessage)

        createSendMessageJob(appMessage)

        result.add(appMessage)
        //  }

        return result
    }

    override fun queryMessage(req: QueryAppMessageReq, pageable: Pageable?): List<AppMessage> {
        var w: Specifications<AppMessage> = Specifications.where({ _, _, cb ->
            cb.equal(cb.literal(1), 1)
        })

        w = w.and({ root, query, cb ->
            val join: Join<*, *> = root.join<MobileUser, AppMessage>(AppMessage::users.name)
            val path = join.get<String>(MobileUser::loginName.name)
            cb.equal(path, req.username)
        })

        if (req.readStatus != null) {
            w = w.and({ root, query, cb ->
                //val join: Join<*, *> = root.join<MobileUser,AppMessage>(AppMessage::users.name)
                val path = root.get<Int>(AppMessage::readStatus.name)
                cb.equal(path, req.readStatus)
            })
        }

        if (req.msgID != null) {
            w = w.and({ root, query, cb ->
                //val join: Join<*, *> = root.join<MobileUser,AppMessage>(AppMessage::users.name)
                val path = root.get<Int>(AppMessage::messageID.name)
                cb.equal(path, req.msgID)
            })
        }

        if (req.begin != null && req.end != null) {
            w = w.and({ root, query, cb ->
                //val join: Join<*, *> = root.join<MobileUser,AppMessage>(AppMessage::users.name)
                val path = root.get<Date>(AppMessage::createDate.name)
                cb.between(path, req.begin, req.end)
            })
        }

        return if (pageable != null)
            appMessageDao.findAll(w, pageable).content
        else
            appMessageDao.findAll(w)

    }

    override fun readMessage(messageID: String): AppMessage {
        var msg = appMessageDao.findOne(messageID) ?: throw StatusAndMessageError("没有此消息:$messageID")

        msg.readStatus = 1

        return appMessageDao.saveAndFlush(msg)

    }

    @Transactional
    override fun createSendMessageJob(msg: AppMessage): List<AppMessageJob> {
        var result = LinkedList<AppMessageJob>()

        msg?.suite.apps.forEach {
            app ->
            msg?.users.forEach { user ->
                val devices = deviceService.findByUser(user, app).forEach {
                    var job = AppMessageJob(msg, it, user,app)

                    job = jobDao.saveAndFlush(job)

                    result.add(job)
                }

            }
        }

        return result
    }

}